<template>
	<e-popup :show="props.show" mode="bottom" bgColor="transparent" :round="props.round" :closeOnClickOverlay="props.closeOnClickOverlay"
		@close="closeHandler">
		<view class="e-cascader e-rela" :style="[cascaderStyle]">
			<view class="e-cascader__mask" v-show="!initialLoaded">
				<e-loading-icon :show="!initialLoaded"></e-loading-icon>
			</view>
			<view class="e-cascader__header ">
				<slot name="toolbar" >
					<toolbar :show="props.showToolbar" :cancelColor="props.cancelColor" :confirmColor="props.confirmColor"
						:cancelText="props.cancelText" :confirmText="props.confirmText" :title="props.title" @cancel="cancel"
						@confirm="confirm">
					</toolbar>
				</slot>
				
				<scroll-view class="e-cascader__header-scroll" scroll-y>
					<view class="e-cascader__header-scroll__box">
						<view class="e-cascader__header-scroll__box-item " :style="[valueStyle]" v-for="(item,index) in values" :key="item"
							@tap="columnIndexChange(index,item)">
							<text class="e-cascader__header-scroll__box-item__text">{{ item.label}}</text>
						</view>
						<view class="e-cascader__header-scroll__box-item "  :style="[valueStyle]">
							<text class="e-cascader__header-scroll__box-item__placeholder"> {{isEnd ? '' :props.placeholder}}</text>
						</view>
					</view>

				</scroll-view>


			</view>
			<e-line color="#e2e2e2"></e-line>
			<scroll-view class="e-cascader__visible" scroll-y :style="[bodyStyle]">
				<cascader-node :columns="columns" :itemHeight="props.itemHeight" :itemCustomStyle="props.itemCustomStyle"
					@click="handleItemClick"></cascader-node>
				<!-- 	<view class="e-cascader__visible-item" :style="[itemStyle]"
					@tap="handlerItemClick(item)">
					<text class="e-cascader__visible-item__text">{{ item.label}}</text>
				</view> -->
			</scroll-view>
			<slot name="foot">
				
			</slot>
		</view>
	</e-popup>
</template>

<script lang="ts">
	import {
		defineComponent
	} from 'vue'
	import mpMixin from "../../libs/mixin/mpMixin";
	
	/**
	 * cascader 按钮
	 * @description cascader 按钮
	 * @tutorial https://www.uviewui.com/components/button.html
	 *
	 * @property {Boolean}			hairline				是否显示按钮的细边框 (默认 true )
	 * @property {String}			appearance				按钮外观，button（按钮），text（纯文本）
	 * @property {String}			type					按钮的预置样式，info，primary，error，warning，success (默认 'info' )
	 * @property {String}			size					按钮尺寸，large，normal，small，mini （默认 normal）
	 * @property {String}			shape					按钮形状，circle（两边为半圆），square（带圆角） （默认 'square' ）
	 * @property {Boolean}			plain					按钮是否镂空，背景色透明 （默认 false）
	 * @property {Boolean}			disabled				是否禁用 （默认 false）
	 * @property {Boolean}			loading					按钮名称前是否带 loading 图标(App-nvue 平台，在 ios 上为雪花，Android上为圆圈) （默认 false）
	 * @property {String | Number}	loadingText				加载中提示文字
	 * @property {String}			loadingMode				加载状态图标类型 （默认 'spinner' ）
	 * @property {String | Number}	loadingSize				加载图标大小 （默认 15 ）
	 * @property {String}			openType				开放能力，具体请看uniapp稳定关于button组件部分说明
	 * @property {String}			formType				用于 <form> 组件，点击分别会触发 <form> 组件的 submit/reset 事件
	 * @property {String}			appParameter			打开 APP 时，向 APP 传递的参数，open-type=launchApp时有效 （注：只微信小程序、QQ小程序有效）
	 * @property {Boolean}			hoverStopPropagation	指定是否阻止本节点的祖先节点出现点击态，微信小程序有效（默认 true ）
	 * @property {String}			lang					指定返回用户信息的语言，zh_CN 简体中文，zh_TW 繁体中文，en 英文（默认 en ）
	 * @property {String}			sessionFrom				会话来源，openType="contact"时有效
	 * @property {String}			sendMessageTitle		会话内消息卡片标题，openType="contact"时有效
	 * @property {String}			sendMessagePath			会话内消息卡片点击跳转小程序路径，openType="contact"时有效
	 * @property {String}			sendMessageImg			会话内消息卡片图片，openType="contact"时有效
	 * @property {Boolean}			showMessageCard			是否显示会话内消息卡片，设置此参数为 true，用户进入客服会话会在右下角显示"可能要发送的小程序"提示，用户点击后可以快速发送小程序消息，openType="contact"时有效（默认false）
	 * @property {String}			dataName				额外传参参数，用于小程序的data-xxx属性，通过target.dataset.name获取
	 * @property {String | Number}	throttleTime			节流，一定时间内只能触发一次 （默认 0 )
	 * @property {String | Number}	hoverStartTime			按住后多久出现点击态，单位毫秒 （默认 0 )
	 * @property {String | Number}	hoverStayTime			手指松开后点击态保留时间，单位毫秒 （默认 200 )
	 * @property {String | Number}	text					按钮文字，之所以通过props传入，是因为slot传入的话（注：nvue中无法控制文字的样式）
	 * @property {String}			icon					按钮图标
	 * @property {String}			color					按钮颜色，支持传入linear-gradient渐变色，设置该属性则按钮的type将失效
	 * @property {Object}			customStyle				定义需要用到的外部样式
	 *
	 * @event {Function}	click			非禁止并且非加载中，才能点击
	 * @event {Function}	getphonenumber	open-type="getPhoneNumber"时有效
	 * @event {Function}	getuserinfo		用户点击该按钮时，会返回获取到的用户信息，从返回参数的detail中获取到的值同uni.getUserInfo
	 * @event {Function}	error			当使用开放能力时，发生错误的回调
	 * @event {Function}	opensetting		在打开授权设置页并关闭后回调
	 * @event {Function}	launchapp		打开 APP 成功的回调
	 * @example <e-cascader></e-cascader>
	 */
	
	export default defineComponent({
		name: "e-cascader",
		mixins: [mpMixin],
	});
</script>

<script lang="ts" setup>
	import {
		ref,
		reactive,
		computed,
		watch,
		provide,
		toRefs
	} from 'vue'
	import {
		cascaderProps,
		cascaderEmits
	} from './props'
	import {
		deepMerge,
		empty
	} from "../../libs/utils"
	import {
		addStyle,
		addUnit
	} from "../../libs/utils/_utils"
	import type {
		StyleProperties
	} from '../../libs/tokens'
	import {
		useDefaultProps
	} from '../../libs/hooks'
	import {
		useLazyLoadConfig,
		Store,
		Node,
		CASCADER_INJECTION_KEY,
		type ECascaderContext,
		type CascaderOption
	} from './util'
	import componentsProps, {
		type DefaultProps
	} from "../../libs/config/componentsProps";
	import cascaderNode from './node.vue'
	import toolbar from '../toolbar/index.vue'
	
	const {
		cascader: cascaderDefaultProps
	} = toRefs(componentsProps);

	const _props = defineProps(cascaderProps)
	const props = useDefaultProps < DefaultProps['cascader'] > (_props, cascaderDefaultProps);
	
	const emit = defineEmits(cascaderEmits)
	const {
		config
	} = useLazyLoadConfig({
		props:props.value.props
	})


	const values = reactive < Array < Node>> ([])
	const columns = ref < Array < Node >> ([])

	const cascaderStyle = computed(() => {
		let style: StyleProperties = {
			borderTopLeftRadius: addUnit(props.value.round),
			borderTopRightRadius: addUnit(props.value.round)
		}
		return deepMerge(style, addStyle(props.value.customStyle as Record<string,any>) as Record<string,any>)
	})
	const valueStyle = computed(() => {
		let style: StyleProperties = {
			marginLeft: addUnit(props.value.valueMargin),
			marginRight: addUnit(props.value.valueMargin)
		}
		return deepMerge(style, addStyle(props.value.customStyle as Record<string,any>) as Record<string,any>)
	})

	const bodyStyle = computed(() => {
		return {
			height: addUnit((props.value.itemHeight as number) * (props.value.visibleItemCount as number))
		}
	})

	let store: Store | null = null
	const initialLoaded = ref(true)
	const isEnd = ref(false)

	const lazyLoad: ECascaderContext['lazyLoad'] = (node, cb) => {
		const cfg = config.value;
		node = node || new Node({}, cfg, undefined, true);
		node.loading = true

		const resolve = (dataList: CascaderOption[]) => {
			const _node = node as Node
			const parent = _node.root ? null : _node
			dataList && store?.appendNodes(dataList, parent as any)
			_node.loading = false
			_node.loaded = true
			_node.childrenData = _node.childrenData || []
			cb && cb(dataList)
			if(_node.level === 0) return
			if ( dataList.length) {
				columns.value = _node.children
			}else{
				isEnd.value = true
			}
			
		}

		cfg.lazyLoad(node, resolve as any)
	}


	const initStore = () => {
		const {
			options
		} = props.value
		const cfg = config.value

		// manualChecked = false


		if (cfg.lazy && empty(props.value.options)) {
			initialLoaded.value = false
			lazyLoad(undefined, (list) => {
				if (list) {
					store = new Store(list, cfg)
					columns.value = store.getNodes()
				}
				initialLoaded.value = true
				// syncCheckedValue(false, true)
			})
		} else {
			// syncCheckedValue(false, true)
			store = new Store(options, cfg)
			columns.value = store.getNodes()
		}
	}
	const columnIndexChange = (index: number, node: Node | {}) => {
		let maxStep = values.length - 1
		
		while(maxStep > index){
			let item = values[maxStep];
			item.parent?.resetChildCheck()
			maxStep--
		}
		values.splice(index, values.length - index)
		if (index === 0) {
			store?.resetChildCheck()
			columns.value = store?.getNodes() || []
		} else {
			(node as Node)?.parent?.resetChildCheck()
			columns.value = (node as Node)?.parent?.children || []
		}
		isEnd.value = false
		emit('change',values.map(item => item.data))
	}

	const handleItemClick = (node: Node) => {
		
		values.splice(node.level - 1, 1, node);
		if(node.loaded){
			node.children.length ? (columns.value = node.children) : (isEnd.value = true)
		}
		emit('change',values.map(item => item.data))

	}

	// 关闭选择器
	const closeHandler = () => {
		if (props.value.closeOnClickOverlay) {
			emit('close')
		}
	}
	// 点击工具栏的取消按钮
	const cancel = () => {
		emit('cancel')
	}
	const confirm = () => {
		emit('confirm',values.map(item => item.data))
	}

	provide(
		CASCADER_INJECTION_KEY,
		reactive({
			config,
			lazyLoad
		})
	)

	watch(() =>[config.value,props.value.options], initStore, {
		deep: true,
		immediate: true,
	})
</script>

<style lang="scss" scoped>
	@import '../../libs/theme/cascader.scss';
</style>
